#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <modbus.h>
#include <errno.h>
#include "custom_handle.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include "shmem.h"
#include "cJSON.h"
#include "list.h"

modbus_t *ctx;

struct list_head mb_node_list_head;

struct mb_node
{
    int key;        // 唯一键值
    char name[128]; // 数据点名称
    int type;       // 数据点类型
    int addr;
};

struct mb_node_list
{
    struct mb_node node;
    struct list_head list;
};

// 寄存器类型选择函数
static int get_register_type(int addr)
{
    if (addr >= 1 && addr <= 9999)
    {
        return 0; // 线圈寄存器
    }
    else if (addr >= 10001 && addr <= 19999)
    {
        return 1; // 离散输入
    }
    else if (addr >= 30001 && addr <= 39999)
    {
        return 3; // 输入寄存器
    }
    else if (addr >= 40001 && addr <= 49999)
    {
        return 4; // 保持寄存器
    }
    return -1; // 无效地址
}

// cJSON数据解析函数
void JSON_data_parse(const char *list)
{
    // 将json字符串转换为cJSON树结构
    cJSON *root = cJSON_Parse(list);
    // 从根节点上获取modbus节点
    cJSON *modbus = cJSON_GetObjectItem(root, "modbus");

    // 从根节点上获取array类型的data节点
    cJSON *arr = cJSON_GetObjectItem(modbus, "data");
    // 遍历数组
    for (int i = 0; i < cJSON_GetArraySize(arr); i++)
    {
        // 分别获取每个数组元素
        cJSON *item = cJSON_GetArrayItem(arr, i);
        // 获取数组元素的key节点
        cJSON *key = cJSON_GetObjectItem(item, "key");
        cJSON *addr = cJSON_GetObjectItem(item, "addr");
        printf("111\n");
        printf("%s:%d\n", key->string, key->valueint);
        printf("%s:%d\n", addr->string, addr->valueint);
        printf("222\n");

        struct mb_node_list *new_node = (struct mb_node_list *)malloc(sizeof(struct mb_node_list));
        if (!new_node)
        {
            printf("内存分配失败，无法添加配置项 %d\n", i + 1);
            continue;
        }

        // 填充节点数据
        new_node->node.key = cJSON_GetObjectItem(item, "key")->valueint;
        strcpy(new_node->node.name, cJSON_GetObjectItem(item, "name")->valuestring);
        new_node->node.type = cJSON_GetObjectItem(item, "type")->valueint;
        new_node->node.addr = cJSON_GetObjectItem(item, "addr")->valueint;

        // 初始化链表节点并添加到链表尾部
        INIT_LIST_HEAD(&new_node->list);
        list_add_tail(&new_node->list, &mb_node_list_head);

        printf("解析配置项 %d: key=%d, name=%s, type=%d, addr=%d\n",
               i + 1, new_node->node.key,
               new_node->node.name, new_node->node.type,
               new_node->node.addr);
    }
    cJSON_Delete(root);
}

struct msgbuf
{
    long type;
    int command;
};

// 线程1：指令线程
void *handler1(void *arg)
{
    struct msgbuf m;
    key_t key = ftok("/home/hq/25031/1.txt", 'b');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("%#x\n", key);
    // 创建或打开消息队列
    int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (msgid == 0)
        {
            msgctl(0, IPC_RMID, NULL);
            msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
        }
        else
        {
            if (errno == EEXIST)
            {
                msgid = msgget(key, 0666);
            }
        }
    }
    printf("msgid = %d\n", msgid);
    while (1)
    {
        msgrcv(msgid, &m, sizeof(m) - sizeof(long), 0, 0);
        printf("m.command=%d\n", m.command);
        if (m.type == 1)
        {
            if (m.command == 0)
            {
                modbus_write_bit(ctx, 0, 0);
                printf("***************led关闭***************\n");
            }
            else if (m.command == 1)
            {
                modbus_write_bit(ctx, 0, 1);
                printf("***************led打开***************\n");
            }
        }
        else if (m.type == 2)
        {
            if (m.command == 0)
            {
                modbus_write_bit(ctx, 1, 0);
                printf("***************buzzer关闭***************\n");
            }
            else if (m.command == 1)
            {
                modbus_write_bit(ctx, 1, 1);
                printf("***************buzzer打开***************\n");
            }
        }
    }
    // msgctl(msgid,IPC_RMID,NULL);
}

// 主线程：点表解析+数据采集
int main(int argc, char const *argv[])
{
    // 读取json文件中的数据
    FILE *fp;
    char buf[4096] = "";
    fp = fopen("./data.JSON", "r");
    if (fp == NULL)
    {
        perror("fopen err");
        return -1;
    }
    fread(buf, 4096, 1, fp);
    printf("%s\n", buf);

    // 初始化链表头
    INIT_LIST_HEAD(&mb_node_list_head);

    // 调用cJSON数据解析函数
    JSON_data_parse(buf);

    pthread_t tid;
    key_t key;
    int shmid;

    char str[65536] = {0};

    // 创建Modbus TCP上下文
    ctx = modbus_new_tcp("192.168.3.159", 502);
    if (ctx == NULL)
    {
        fprintf(stderr, "无法创建Modbus上下文\n");
        return -1;
    }
    // 连接Modbus从机
    if (modbus_connect(ctx) == -1)
    {
        fprintf(stderr, "连接失败: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    // 设置从机ID
    modbus_set_slave(ctx, 1);
    modbus_connect(ctx);

    // 创建线程
    if (pthread_create(&tid, NULL, handler1, NULL) != 0)
    {
        perror("无法创建采集线程");
        modbus_close(ctx);
        modbus_free(ctx);
        return -1;
    }

    // 1. 尝试创建文件（如果不存在）
    const char *filepath = "/home/hq/25031/1.txt";
    int fd = open(filepath, O_CREAT | O_RDONLY, 0666);
    if (fd == -1)
    {
        perror("open/create file failed");
        return -1;
    }
    close(fd); // 不需要保持打开，ftok只需要文件存在

    struct shm_param para;
    SharedData data;
    if (shm_init(&para, "ShemeData", sizeof(SharedData)) < 0)
    {
        printf("init err\n");
        return -1;
    }

    SharedData *addr = (SharedData *)shm_getaddr(&para);
    if (addr == NULL)
    {
        perror("shm_getaddr failed");
        return -1;
    }
    // 初始化信号量
    sem_init(&data.mutex, 1, 1);      // 初始值1：允许访问
    sem_init(&data.data_ready, 1, 1); // 初始值0：数据未就绪

    addr->count = 0;

    // 主循环采集数据
    printf("开始数据采集循环...\n");
    while (1)
    {

        // 等待读取程序完成上一轮数据处理
        sem_wait(&data.data_ready);
        sem_wait(&data.mutex);

        int i = 0;
        // 遍历链表，根据类型读取数据
        struct list_head *pos;
        struct mb_node_list *node;

        list_for_each(pos, &mb_node_list_head)
        {
            node = list_entry(pos, struct mb_node_list, list);
            Modbus_data *data_point = &addr->data_point[i];
            // 初始化数据点
            data_point->key = node->node.key;
            data_point->type = node->node.type;
            data_point->dev_type = 1; // Modbus设备
            data_point->ret = -1;     // 默认标记为失败

            int ret = -1;
            uint16_t reg_value = 0;

            // 根据寄存器类型选择读取函数
            switch (get_register_type(node->node.addr))
            {
            case 0: // 线圈状态(0x)
                ret = modbus_read_bits(ctx, node->node.addr - 1, 1, &reg_value);
                break;
            case 1: // 离散输入(1x)
                ret = modbus_read_input_bits(ctx, node->node.addr - 10001, 1, &reg_value);
                break;
            case 3: // 输入寄存器(3x)
                ret = modbus_read_input_registers(ctx, node->node.addr - 30001, 1, &reg_value);
                break;
            case 4: // 保持寄存器(4x)
                ret = modbus_read_registers(ctx, node->node.addr - 40001, 1, &reg_value);
                break;
            default:
                printf("未知寄存器类型: addr=%d\n", node->node.addr);
                continue;
            }

            if (ret == 1)
            {
                // 保存旧值
                data_point->old_val = data_point->new_val;

                // 根据数据类型处理新值
                switch (node->node.type)
                {
                case 1: // bool类型
                    data_point->new_val.b_val = (reg_value != 0);
                    printf("[%d] %s: 地址=%d, 类型=bool, 值=%s\n",
                           data_point->key, node->node.name,
                           node->node.addr,
                           data_point->new_val.b_val ? "true" : "false");
                    break;
                case 2: // int类型
                    data_point->new_val.i_val = (int)reg_value;
                    printf("[%d] %s: 地址=%d, 类型=int, 值=%d\n",
                           data_point->key, node->node.name,
                           node->node.addr, data_point->new_val.i_val);
                    break;
                case 3: // float类型
                    data_point->new_val.f_val = (float)reg_value / 10.0;
                    printf("[%d] %s: 地址=%d, 类型=float, 值=%.1f\n",
                           data_point->key, node->node.name,
                           node->node.addr, data_point->new_val.f_val);
                    break;
                default:
                    printf("错误: 未知数据类型 - type=%d\n", node->node.type);
                    continue;
                }

                data_point->ret = 0; // 标记为成功
                i++;                 // 索引递增，准备下一个节点
            }
            else
            {
               printf("错误: 读取失败 - %s, addr=%d, err=%s\n", 
                       node->node.name, node->node.addr, modbus_strerror(errno));
                // 保留旧值，标记为失败
                data_point->ret = -1;
            }
        }
        data.count = i;
printf("本轮采集完成，成功采集 %u 个数据点\n", i);
        shm_write(&para, &data, sizeof(SharedData));

        sem_post(&data.data_ready);
        sem_post(&data.mutex); // 释放锁
       

        sleep(1);
        printf("-------------------------------------------\n");
    }
    // 等待线程结束（实际上不会结束）
    pthread_join(tid, NULL);
    // 清理
    sem_destroy(&addr->mutex);
    sem_destroy(&addr->data_ready);
    modbus_close(ctx);
    modbus_free(ctx);
    shm_del(&para);
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}